package cn.edu.sgu.www.mhxysy.service.qiling.impl;

import cn.edu.sgu.www.mhxysy.consts.CustomMessages;
import cn.edu.sgu.www.mhxysy.consts.IdentifierPrefixes;
import cn.edu.sgu.www.mhxysy.dto.qiling.QilingAttributeDTO;
import cn.edu.sgu.www.mhxysy.entity.qiling.Qiling;
import cn.edu.sgu.www.mhxysy.entity.qiling.QilingAttribute;
import cn.edu.sgu.www.mhxysy.entity.qiling.QilingCategory;
import cn.edu.sgu.www.mhxysy.entity.qiling.QilingViewAttribute;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.mapper.equipment.EquipmentTypeMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingCategoryMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingMapper;
import cn.edu.sgu.www.mhxysy.mapper.qiling.QilingViewAttributeMapper;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.service.qiling.QilingAttributeService;
import cn.edu.sgu.www.mhxysy.util.CollectionUtils;
import cn.edu.sgu.www.mhxysy.util.MathUtils;
import cn.edu.sgu.www.mhxysy.util.ObjectUtils;
import cn.edu.sgu.www.mhxysy.util.StringUtils;
import cn.edu.sgu.www.mhxysy.vo.except.AttributeVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Service
public class QilingAttributeServiceImpl implements QilingAttributeService {

	private final QilingMapper qilingMapper;
	private final EquipmentTypeMapper equipmentTypeMapper;
	private final QilingCategoryMapper qilingCategoryMapper;
	private final QilingAttributeMapper qilingAttributeMapper;
	private final QilingViewAttributeMapper qilingViewAttributeMapper;

	@Autowired
	public QilingAttributeServiceImpl(
			QilingMapper qilingMapper,
			EquipmentTypeMapper equipmentTypeMapper,
			QilingCategoryMapper qilingCategoryMapper,
			QilingAttributeMapper qilingAttributeMapper,
			QilingViewAttributeMapper viewAttributeMapper) {
		this.qilingMapper = qilingMapper;
		this.equipmentTypeMapper = equipmentTypeMapper;
		this.qilingCategoryMapper = qilingCategoryMapper;
		this.qilingAttributeMapper = qilingAttributeMapper;
		this.qilingViewAttributeMapper = viewAttributeMapper;
	}

	@Override
	public void allocate(String qilingId) {
		Qiling qiling = qilingMapper.selectById(qilingId);
		QilingCategory qilingCategory = qilingCategoryMapper.selectById(qiling.getCategoryId());

		int grade = qilingCategory.getGrade();
		Integer equipmentId = equipmentTypeMapper.selectTopType(qilingCategory.getEquipmentId());

		// 查询已有的器灵属性
		List<QilingAttribute> attributes = selectByQilingId(qilingId);
		// 得到器灵已有的属性类型ID列表
		List<Integer> propertyIds = attributes.stream().map(new Function<QilingAttribute, Integer>() {
			@Override
			public Integer apply(QilingAttribute qilingAttribute) {
				return qilingAttribute.getPropertyId();
			}
		}).collect(Collectors.toList());

		// 查询器灵预览属性列表
		QueryWrapper<QilingViewAttribute> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("grade", grade);
		queryWrapper.eq("equipment_id", equipmentId);
		queryWrapper.notIn(
				CollectionUtils.isNotEmpty(propertyIds),
				"property_id", propertyIds
		);

		List<QilingViewAttribute> viewAttributes = qilingViewAttributeMapper.selectList(queryWrapper);

		// 预览属性列表为空，则说明器灵属性都已经添加过了
		if (viewAttributes.isEmpty()) {
			throw new GlobalException(ResponseCode.BAD_REQUEST, "该器灵已经没有可添加的属性了。");
		}

		String uuid = StringUtils.uuid();
		// 将时间戳字符串转为long类型
		long key = Long.parseLong(uuid);

		for (QilingViewAttribute viewAttribute : viewAttributes) {
			Integer min = viewAttribute.getMin();
			Integer max = viewAttribute.getMax();
			Integer propertyId = viewAttribute.getPropertyId();
			// 得到范围内的随机属性值
			Integer propertyValue = MathUtils.random(min, max);

			QilingAttribute attribute = new QilingAttribute();

			attribute.setId(IdentifierPrefixes.PREFIX_QLSX + key);
			attribute.setQilingId(qilingId);
			attribute.setPropertyId(propertyId);
			attribute.setPropertyValue(propertyValue);

			qilingAttributeMapper.insert(attribute);
			key++;
		}
	}

	@Override
	public void insert(QilingAttributeDTO qilingAttributeDTO) {
		QilingAttribute qilingAttribute = toEntity(qilingAttributeDTO);

		qilingAttribute.setId(qilingAttribute.uuid());

		qilingAttributeMapper.insert(qilingAttribute);
	}

	@Override
	public void deleteById(String id) {
		qilingAttributeMapper.deleteById(id);
	}

	@Override
	public void updateById(QilingAttributeDTO qilingAttributeDTO) {
		ObjectUtils.requireNonNull(qilingAttributeDTO.getId(), CustomMessages.ID_NOT_NULL);

		QilingAttribute qilingAttribute = toEntity(qilingAttributeDTO);

		qilingAttributeMapper.updateById(qilingAttribute);
	}

	@Override
	public List<AttributeVO> selectAttributes(String qilingId) {
		return qilingAttributeMapper.selectAttributes(qilingId);
	}

	@Override
	public List<QilingAttribute> selectByQilingId(String qilingId) {
		QueryWrapper<QilingAttribute> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("qiling_id", qilingId);
		queryWrapper.orderByAsc("property_id");

		return qilingAttributeMapper.selectList(queryWrapper);
	}

	/**
	 * 验证属性值是否在取值范围内
	 * @param qilingAttributeDTO 器灵属性信息
	 * @return boolean
	 */
	private boolean validateRange(QilingAttributeDTO qilingAttributeDTO) {
		Qiling qiling = qilingMapper.selectById(qilingAttributeDTO.getQilingId());
		QilingCategory qilingCategory = qilingCategoryMapper.selectById(qiling.getCategoryId());

		Integer grade = qilingCategory.getGrade();
		Integer equipmentId = equipmentTypeMapper.selectTopType(qilingCategory.getEquipmentId());

		// 2、验证属性范围
		QueryWrapper<QilingViewAttribute> queryWrapper = new QueryWrapper<>();

		queryWrapper.eq("grade", grade);
		queryWrapper.eq("equipment_id", equipmentId);
		queryWrapper.eq("property_id", qilingAttributeDTO.getPropertyId());

		QilingViewAttribute viewAttribute = qilingViewAttributeMapper.selectOne(queryWrapper);

		if (viewAttribute != null) {
			Integer value = qilingAttributeDTO.getPropertyValue();
			Integer min = viewAttribute.getMin();
			Integer max = viewAttribute.getMax();

			if (value > max || value < min) {
				throw new GlobalException(ResponseCode.FORBIDDEN, "器灵属性值不合法，数值范围为："+ min + "~" + max);
			}
		}

		return true;
	}

	private QilingAttribute toEntity(QilingAttributeDTO qilingAttributeDTO) {
		boolean validateRange = validateRange(qilingAttributeDTO);

		if (validateRange) {
			QilingAttribute qilingAttribute = new QilingAttribute();

			qilingAttribute.setId(qilingAttributeDTO.getId());
			qilingAttribute.setQilingId(qilingAttributeDTO.getQilingId());
			qilingAttribute.setPropertyId(qilingAttributeDTO.getPropertyId());
			qilingAttribute.setPropertyValue(qilingAttributeDTO.getPropertyValue());

			return qilingAttribute;
		}

		return null;
	}

}